<?php
/**
 * +----------------------------------------------------------------------
 * | Author: 罗极
 * +----------------------------------------------------------------------
 * | Description: RouterManager.php
 * +----------------------------------------------------------------------
 * | User: Administrator Date: 8/20/ 0020 Time: 10:15
 * +----------------------------------------------------------------------
 */

namespace Framework\Router;
use Framework\Router\Interfaces\{RouteHttpPost,RouteHttpGet,RouteHttpAny,RouteForward,RouteGroup};
use Framework\Router\Constant\{RequestMethod,DefaultKey};
use Framework\Router\Exception\{RouteSetException,WrongMethodException,InvalidPatternException,NotFoundException};
use Framework\Router\Abstracts\RequestRouter;

class Router implements
    RouteHttpPost,
    RouteHttpGet,
    RouteHttpAny,
    RouteForward,
    RouteGroup
{
    private function __construct(){}
    private function __clone(){}

    public static $routes = [];

    public static function forward(string $url, array $params = []) : RequestRouter
    {
        $url = ltrim($url, '/');
        $url = explode('.', $url)[0];
        $url = explode('?', $url)[0];

        if(empty($url)) { // default
            return new Class(
                        DefaultKey::DefaultModule,
                        DefaultKey::DefaultController,
                        DefaultKey::DefaultAction) extends RequestRouter {};
        }

        // 正常没有设置路由访问
        if(!isset(self::$routes[$url])) {
            $arr    = explode('/', $url);
            $module = $arr[0];
            $controller = $arr[1] ?? DefaultKey::DefaultController;
            $action = $arr[2] ?? DefaultKey::DefaultAction;
            unset($arr[0],$arr[1],$arr[2]);

            if(isset($arr) and !empty($arr)) {
                $arr = array_values($arr);
                for($i = 0 ; $i < count($arr); $i ++) {
                    $_GET[$arr[$i]] = $arr[++$i] ?? '';
                }
            }
            return new Class($module,$controller,$action) extends RequestRouter {};
        }


        // 已经设置过路由的情况
        /**@var $routeUnit RouteUnit**/
        $routeUnit = self::$routes[$url];

        $method = $routeUnit->getMethod();

        if(REQUEST_METHOD != $method) {
            throw new WrongMethodException(sprintf(
                '不正确的请求方式 : [%s]',
                REQUEST_METHOD
            ));
        }

        if(!empty($pattern = $routeUnit->getPattern())) {

            $requestData = ($method == RequestMethod::POST) ? $_POST : $_GET;

            foreach($pattern as $key => $pat) {
                if(isset($requestData[$key])) {
                    $ok = preg_match($pat, $requestData[$key]);

                    if($ok == 0) {
                        throw new InvalidPatternException(sprintf(
                            '参数不符合要求 : [%s => %s]',
                            $key,
                            $requestData[$key]
                        ));
                    }

                }
            }
        }


        $callback = $routeUnit->getCallback();

        if(is_callable($callback)) {
            $callback();
        }

        return new Class($routeUnit->getModule(), $routeUnit->getController(), $routeUnit->getAction()) extends RequestRouter {};
    }

    public static function post(string $route, string $link, array $pattern = [], $callback = '')
    {
        self::any($route, $link, $pattern, $callback, RequestMethod::POST);
    }

    public static function get(string $route, string $link,  array $pattern = [], $callback = '')
    {
        self::any($route, $link, $pattern, $callback, RequestMethod::GET);
    }

    public static function any(string $route, string $link,  array $pattern = [], $callback = '', string $method = '')
    {
        if(!in_array(strtoupper($method), RequestMethod::ConstArr)) {
            throw new RouteSetException('设置路由失败,错误的HTTP_METHOD');
        }
        $route = ltrim($route, '/');
        self::$routes[$route] = new RouteUnit($route, $link, $pattern, $callback, $method);
    }

    public static function group(string $parent, array $group, string $method = '')
    {
        foreach($group as $g) {
            self::any(
                $parent.'/'.ltrim($g[DefaultKey::GroupArrRoute], '/'),
                $g[DefaultKey::GroupArrLink],
                $g[DefaultKey::GroupArrPattern],
                $g[DefaultKey::GroupArrCallBack],
                $method
            );
        }
    }


}